import { Vec3, math } from "cc";
import { Game } from "../core/Game";
import { Databus } from "../core/Databus";
import { BilliardGame } from "../game/BilliardGame";
import { UserAttribute } from "../core/UserAttribute";
import { WebFrameController } from "./WebFrameController";
import { EventManager } from "../core/EventManager";
import { ResourceManager } from "../framework/ResourceManager";
import { NetHitMainBallFrame, NetKeyFrame } from "../core/WebSocketData";
import { PlayUser } from "../core/PlayUser";
import { UniformFunction } from "../platform/UniformFunction";

const databus = Databus.Instance();
export class WebSocketAdaptor {
  private static instance: WebSocketAdaptor = null as unknown as WebSocketAdaptor;
  
  public static Instance() {
    if (WebSocketAdaptor.instance) {
      return WebSocketAdaptor.instance;
    }
    WebSocketAdaptor.instance = new WebSocketAdaptor();
    return WebSocketAdaptor.instance;
  }
  constructor() {
  }

  // 处理接收消息
  processRecvMessage(body: any) {
    var data =  JSON.parse(body);
    if (data.header.oper === 'keyframe') {
      this.processKeyFrame(data);
    } else if (data.header.oper === 'aimline') {
      this.processAimLine(data);
    } else if (data.header.oper === 'mainballfree') {
      this.processMainBall(data);
    } else if (data.header.oper === 'user') {
      this.processUserStatus(data);
    } else if (data.header.oper === 'start') {
      this.processStartGame(data);
    } else if (data.header.oper === 'over') {
      this.processGameOver(data)
    } else if (data.header.oper === 'syncstepover') {
      this.processSyncStepOver(data);
    } else if (data.header.oper === 'room') {
      if (data.data.status === 'full') {
        new UniformFunction().showInfoToast('房间已满，请返回到首页', 3000);
      }
      if (data.data.status === 'nonexist') {
        new UniformFunction().showInfoToast('房间已解散，请返回到首页', 3000);
      }
    } else if(data.header.oper === 'chat') {
      this.processChatContent(data);
    } else if (data.header.oper === 'mainballhitted') {
      this.processMainBallHitted(data);
    } else if (data.header.oper === 'gamefirstframe') {
      this.processGameFirstFrame(data);
    } else if (data.header.oper === 'askconfirm') {
      this.processAskConfirm(data);
    }
  }
  // 击打白球时的信息
  private processMainBallHitted(data: any) {
    if (data.data.step !== Game.Instance().currentStep) {
      return ;
    }
    if (BilliardGame.Instance().actionStage.canForceHit()) {
      // 先开始收集部分帧，然后延迟1s开球
      WebFrameController.Instance().frameSimulation.startRecvFrame();
      const hm = data.data as NetHitMainBallFrame;
      WebFrameController.Instance().frameSimulation.addKeyFrame(hm.initFrame);
      console.log('recv main ball hitted ', hm, Date.now());
      setTimeout(() => {
        EventManager.Instance().Emit('WebQiuGanForceEnded', hm.hitMainBall);
      }, 1000);
    }
  }
  private processUserStatus(data: any) {
    const ors = Game.Instance().playUsers[1].status; 
    const ua = new UserAttribute();
    ua.setUserInfo(data.data.userAttribute);
    Game.Instance().setOppoPlayUser(data.data.status, ua);
    // 设置头像资源
    ResourceManager.Instance().loadImageSpriteFrame(
      ResourceManager.OppoUserHeaderImage, ua.avatarUrl, ResourceManager.Instance().getImageExt(ua.avatarUrl)
    );

    const oppo = Game.Instance().getPlayUserIndex(1);
    if (oppo.isLeavedStatus() && ors !== PlayUser.StatusLeaved) {
      EventManager.Instance().Emit('OppoUserLeave',{});
    }
    console.log('process user status ', data.data);
  }
  private processStartGame(data: any) {
    Game.Instance().setSide(data.data.side);

    Game.Instance().playUsers[0].started();
    Game.Instance().playUsers[1].started();
    Game.Instance().playUsers[0].restartStepTime();
    Game.Instance().playUsers[1].restartStepTime();
    if (databus.sceneStack.isInRoomPage()) {
      EventManager.Instance().Emit('RestartGame', {});
    } else {
      databus.sceneStack.toRoomPage();
    }
  }
  // 接收到关键帧信息
  private processKeyFrame(data: any) {
    if (data.data.step === Game.Instance().currentStep) {
      const frame = data.data as NetKeyFrame;
      if (WebFrameController.Instance().frameSimulation.isSameStep(frame.step)) {
        WebFrameController.Instance().frameSimulation.addKeyFrame(frame);
      } else {
        // 从当前帧开始根上进度
        WebFrameController.Instance().fastCatchStepFrame(data.data.step, frame);
      }
    } else if (data.data.step > Game.Instance().currentStep) { // 对手比我走的快, 必须实时同步跟进
      const frame = data.data as NetKeyFrame;
      WebFrameController.Instance().fastCatchStepFrame(data.data.step, frame);
    }
  }
  // 对齐整个游戏的第1帧
  private processGameFirstFrame(data: any) {
    if (data.data.step === Game.Instance().currentStep) {
      WebFrameController.Instance().frameSimulation.simulateOppoFirstFrame(data.data);
    }
  }
  // 游戏第1帧
  private processGameOver(data: any) {
    Game.Instance().endGame(data.data.userId, data.data.reason);
    EventManager.Instance().Emit('WebEndGame', data.data);
  }
  // 同步第1次击打的球是哪个
  private processSyncStepOver(data: any) {
    if (data.data.step === Game.Instance().currentStep) {
      WebFrameController.Instance().stepEndData = data.data;
      // 已经收到最后一帧，但是当前状态还未开始击球，那么快速同步到一致状态
      if (BilliardGame.Instance().actionStage.canForceHit()) {
        WebFrameController.Instance().fastSyncEndFrame(data.data);
      }
    } else if (data.data.step > Game.Instance().currentStep) {
      WebFrameController.Instance().fastSyncEndFrame(data.data);
    }
  }
  // 瞄准球
  private processAimLine(data: any) {
    if (data.data.step === Game.Instance().currentStep) {
      const qg = {
        endPoint: new Vec3(data.data.endPoint.x, data.data.endPoint.y, data.data.endPoint.z),
        defaultPoint: new Vec3(data.data.defaultPoint.x, data.data.defaultPoint.y, data.data.defaultPoint.z),
        qiuganRotation: new math.Quat(data.data.qiuganRotation.x, data.data.qiuganRotation.y, data.data.qiuganRotation.z, data.data.qiuganRotation.w)
      }
      EventManager.Instance().Emit('QiuGanPositionController', qg);
    }
  }
  // 自由球：重新设置白球位置
  private processMainBall(data: any) {
    if (data.data.step === Game.Instance().currentStep) {
      if (BilliardGame.Instance().actionStage.canForceHit()) {
        EventManager.Instance().Emit('WebResetMainBallPosition',
          new Vec3(data.data.position.x, data.data.position.y, data.data.position.z)
        );
      }
    }
  }

  private processChatContent(data: any) {
    EventManager.Instance().Emit('OppoNetChatContent', data.data);
  }

  private processAskConfirm(data: any) {
    if (data.data.step > Game.Instance().currentStep) {
      return;
    }
    if (data.data.askType === 0) { // 如果已经有最后一帧信息，重新传递最后一帧
      WebFrameController.Instance().resendStepOverData(data.data.step);
      return;
    }
  }
}

